#ifndef DWG_SCENE_H
#define DWG_SCENE_H

#include <osg/Matrixd>
#include <osg/Group>
#include <osg/MatrixTransform>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Vec3d>
#include <osgText/Text>
#include <osgUtil/SmoothingVisitor>
#include <map>
#include <vector>
#include <limits>

// Forward declarations for libredwg
extern "C"
{
#include "dwg.h"
}

// 定义几何元素的结构体
struct PointElement
{
    osg::Vec3d position;
    osg::Vec4 color;

    PointElement(const osg::Vec3d &pos, const osg::Vec4 &c) : position(pos), color(c) {}
};

struct LineElement
{
    osg::Vec3d start;
    osg::Vec3d end;
    osg::Vec4 color;

    LineElement(const osg::Vec3d &s, const osg::Vec3d &e, const osg::Vec4 &c) : start(s), end(e), color(c) {}
};

struct TextElement
{
    osg::Vec3d position;
    osg::ref_ptr<osgText::Text> text;
    osg::Vec4 color;

    TextElement(const osg::Vec3d &pos, const osg::ref_ptr<osgText::Text>& t, const osg::Vec4 &c) : position(pos), text(t), color(c) {}
};

struct ColoredVertices
{
    std::vector<osg::Vec3d> vertices;
    osg::Vec4 color;

    ColoredVertices(const std::vector<osg::Vec3d> &verts, const osg::Vec4 &c) : vertices(verts), color(c) {}
};

// 新增结构体以支持更多实体类型
struct DimensionElement
{
    std::vector<osg::Vec3d> lines;  // 尺寸线顶点
    std::vector<osg::Vec3d> arrows; // 箭头顶点
    osg::Vec3d textPosition;
    std::string text;
    osg::Vec4 color;

    DimensionElement(const std::vector<osg::Vec3d> &l,
                     const std::vector<osg::Vec3d> &a,
                     const osg::Vec3d &tp,
                     const std::string &t,
                     const osg::Vec4 &c) : lines(l), arrows(a), textPosition(tp), text(t), color(c) {}
};

struct HatchElement
{
    std::vector<std::vector<osg::Vec3d>> boundaries; // 填充边界
    std::vector<osg::Vec3d> pattern;                 // 填充图案线
    osg::Vec4 color;
    bool isSolid; // 是否为实心填充

    HatchElement(const std::vector<std::vector<osg::Vec3d>> &b,
                 const std::vector<osg::Vec3d> &p,
                 const osg::Vec4 &c,
                 bool solid) : boundaries(b), pattern(p), color(c), isSolid(solid) {}
};

struct FaceElement
{
    std::vector<osg::Vec3d> vertices;
    osg::Vec4 color;

    FaceElement(const std::vector<osg::Vec3d> &verts, const osg::Vec4 &c) : vertices(verts), color(c) {}
};

class bounds
{
public:
    bounds() : _min(DBL_MAX, DBL_MAX, DBL_MAX), _max(-DBL_MAX, -DBL_MAX, -DBL_MAX) {}
    inline void expandBy(const osg::Vec3d &v)
    {
        if (v.x() < _min.x())
            _min.x() = v.x();
        if (v.x() > _max.x())
            _max.x() = v.x();

        if (v.y() < _min.y())
            _min.y() = v.y();
        if (v.y() > _max.y())
            _max.y() = v.y();

        if (v.z() < _min.z())
            _min.z() = v.z();
        if (v.z() > _max.z())
            _max.z() = v.z();
    }
    inline void makeMinValid()
    {
        // we count on _min to offset the whole scene
        // so, we make sure its at 0,0,0 if
        // bounds are not set (anyway, the scene should be empty,
        // if we need to set any value of _min to 0).
        if (_min.x() == DBL_MAX)
            _min.x() = 0;
        if (_min.y() == DBL_MAX)
            _min.y() = 0;
        if (_min.z() == DBL_MAX)
            _min.z() = 0;
    }
    osg::Vec3d _min;
    osg::Vec3d _max;
};

// Helper functions for creating geometries
static inline osg::Geometry *createPtGeometry(osg::PrimitiveSet::Mode pointType, osg::Vec3Array *vertices, const osg::Vec4 &color)
{
    osg::Geometry *geom = new osg::Geometry;
    geom->setVertexArray(vertices);
    geom->addPrimitiveSet(new osg::DrawArrays(pointType, 0, vertices->size()));
    osg::Vec4Array *colors = new osg::Vec4Array;
    colors->push_back(color);
    geom->setColorArray(colors, osg::Array::BIND_OVERALL);
    osg::Vec3Array *norms = new osg::Vec3Array;
    norms->push_back(osg::Vec3(0, 0, 1));
    geom->setNormalArray(norms, osg::Array::BIND_OVERALL);
    return geom;
}

static inline osg::Geometry *createLnGeometry(osg::PrimitiveSet::Mode lineType, osg::Vec3Array *vertices, const osg::Vec4 &color)
{
    osg::Geometry *geom = new osg::Geometry;
    geom->setVertexArray(vertices);
    geom->addPrimitiveSet(new osg::DrawArrays(lineType, 0, vertices->size()));
    osg::Vec4Array *colors = new osg::Vec4Array;
    colors->push_back(color);
    geom->setColorArray(colors, osg::Array::BIND_OVERALL);
    osg::Vec3Array *norms = new osg::Vec3Array;
    norms->push_back(osg::Vec3(0, 0, 1));
    geom->setNormalArray(norms, osg::Array::BIND_OVERALL);
    geom->setUseVertexBufferObjects(true);
    geom->setDataVariance(osg::Object::STATIC);
    return geom;
}

static inline osg::Geometry *createTriGeometry(osg::Vec3Array *vertices, osg::Vec3Array *normals, const osg::Vec4 &color)
{
    osg::Geometry *geom = new osg::Geometry;
    geom->setVertexArray(vertices);
    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, vertices->size()));
    osg::Vec4Array *colors = new osg::Vec4Array;
    colors->push_back(color);
    geom->setColorArray(colors, osg::Array::BIND_OVERALL);
    geom->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
    return geom;
}

class DwgSceneLayer : public osg::Referenced
{
public:
    DwgSceneLayer(const std::string &name) : _name(name) {}
    virtual ~DwgSceneLayer() {}

    void addPoint(osg::Vec3d &v, const osg::Vec4 &color)
    {
        _points.emplace_back(PointElement(v, color));
    }
    void addLine(osg::Vec3d &s, osg::Vec3d &e, const osg::Vec4 &color)
    {
        _lines.emplace_back(LineElement(s, e, color));
    }
    void addLineStrip(std::vector<osg::Vec3d> &vertices, const osg::Vec4 &color)
    {
        _linestrips.emplace_back(ColoredVertices(vertices, color));
    }
    void addLineLoop(std::vector<osg::Vec3d> &vertices, const osg::Vec4 &color)
    {
        _lineloops.emplace_back(ColoredVertices(vertices, color));
    }
    void addTriangles(std::vector<osg::Vec3d> &vertices, const osg::Vec4 &color)
    {
        _triangles.emplace_back(ColoredVertices(vertices, color));
    }
    void addQuads(std::vector<osg::Vec3d> &vertices, const osg::Vec4 &color)
    {
        _quads.emplace_back(ColoredVertices(vertices, color));
    }
    void addText(osg::Vec3d &point, osg::ref_ptr<osgText::Text> text, const osg::Vec4 &color)
    {
        _texts.emplace_back(TextElement(point, text, color));
    }

    // 新增方法以支持更多实体类型
    void addDimension(const std::vector<osg::Vec3d> &lines,
                      const std::vector<osg::Vec3d> &arrows,
                      const osg::Vec3d &textPosition,
                      const std::string &text,
                      const osg::Vec4 &color)
    {
        _dimensions.emplace_back(DimensionElement(lines, arrows, textPosition, text, color));
    }

    void addHatch(const std::vector<std::vector<osg::Vec3d>> &boundaries,
                  const std::vector<osg::Vec3d> &pattern,
                  const osg::Vec4 &color,
                  bool isSolid)
    {
        _hatches.emplace_back(HatchElement(boundaries, pattern, color, isSolid));
    }

    void addFace(const std::vector<osg::Vec3d> &vertices, const osg::Vec4 &color)
    {
        _faces.emplace_back(FaceElement(vertices, color));
    }

    void layer2osg(osg::Group *root, bounds &b)
    {
        osg::Geode *geode = new osg::Geode;
        geode->setName(_name);
        bool hasdata = false;
        if (_points.size())
        {
            osg::Geode *geode = new osg::Geode;
            osg::Vec3Array *vertices = new osg::Vec3Array;
            osg::Vec4 color;
            for (std::vector<PointElement>::iterator itr = _points.begin();
                 itr != _points.end();
                 ++itr)
            {
                 osg::Vec3 v((*itr).position.x() - b._min.x(), (*itr).position.y() - b._min.y(), (*itr).position.z() - b._min.z());
                vertices->push_back(v);
                //scenebounds.expandBy((*itr).position);
                color = (*itr).color;
            }
            geode->addDrawable(createPtGeometry(osg::PrimitiveSet::POINTS, vertices, color));
            root->addChild(geode);
        }
        if (_lines.size())
        {
            osg::Geode *geode = new osg::Geode;
            osg::Vec3Array *vertices = new osg::Vec3Array;
            osg::Vec4 color;
            for (std::vector<LineElement>::iterator itr = _lines.begin();
                 itr != _lines.end();
                 ++itr)
            {
                vertices->push_back(osg::Vec3((*itr).start.x()- b._min.x(), (*itr).start.y()- b._min.y(), (*itr).start.z()- b._min.z()));
                vertices->push_back(osg::Vec3((*itr).end.x()- b._min.x(), (*itr).end.y()- b._min.y(), (*itr).end.z()- b._min.z()));

                color = (*itr).color;
            }
            geode->addDrawable(createLnGeometry(osg::PrimitiveSet::LINES, vertices, color));
            root->addChild(geode);
        }
        if (_linestrips.size())
        {
            osg::Geode *geode = new osg::Geode;
            for (std::vector<ColoredVertices>::iterator itr = _linestrips.begin();
                 itr != _linestrips.end();
                 ++itr)
            {
                osg::Vec3Array *vertices = new osg::Vec3Array;
                for (std::vector<osg::Vec3d>::const_iterator vitr = (*itr).vertices.begin();
                     vitr != (*itr).vertices.end();
                     ++vitr)
                {
                    vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                    //scenebounds.expandBy(*vitr);
                }
                geode->addDrawable(createLnGeometry(osg::PrimitiveSet::LINE_STRIP, vertices, (*itr).color));
            }
            root->addChild(geode);
        }
        if (_lineloops.size())
        {
            osg::Geode *geode = new osg::Geode;
            for (std::vector<ColoredVertices>::iterator itr = _lineloops.begin();
                 itr != _lineloops.end();
                 ++itr)
            {
                osg::Vec3Array *vertices = new osg::Vec3Array;
                for (std::vector<osg::Vec3d>::const_iterator vitr = (*itr).vertices.begin();
                     vitr != (*itr).vertices.end();
                     ++vitr)
                {
                    vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                   // scenebounds.expandBy(*vitr);
                }
                geode->addDrawable(createLnGeometry(osg::PrimitiveSet::LINE_LOOP, vertices, (*itr).color));
            }
            root->addChild(geode);
        }
        if (_triangles.size())
        {
            osg::Geode *geode = new osg::Geode;
            for (std::vector<ColoredVertices>::iterator itr = _triangles.begin();
                 itr != _triangles.end();
                 ++itr)
            {
                osg::Vec3Array *vertices = new osg::Vec3Array;
                for (std::vector<osg::Vec3d>::const_iterator vitr = (*itr).vertices.begin();
                     vitr != (*itr).vertices.end();
                     ++vitr)
                {
                    vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                    //scenebounds.expandBy(*vitr);
                }
                geode->addDrawable(createLnGeometry(osg::PrimitiveSet::TRIANGLES, vertices, (*itr).color));
            }
            root->addChild(geode);
        }
        if (_quads.size())
        {
            osg::Geode *geode = new osg::Geode;
            for (std::vector<ColoredVertices>::iterator itr = _quads.begin();
                 itr != _quads.end();
                 ++itr)
            {
                osg::Vec3Array *vertices = new osg::Vec3Array;
                for (std::vector<osg::Vec3d>::const_iterator vitr = (*itr).vertices.begin();
                     vitr != (*itr).vertices.end();
                     ++vitr)
                {
                    vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                    //scenebounds.expandBy(*vitr);
                }
                geode->addDrawable(createLnGeometry(osg::PrimitiveSet::QUADS, vertices, (*itr).color));
            }
            root->addChild(geode);
        }
        if (_texts.size())
        {
            osg::Geode *geode = new osg::Geode;
            for (std::vector<TextElement>::iterator itr = _texts.begin();
                 itr != _texts.end();
                 ++itr)
            {
                osg::ref_ptr<osgText::Text> &text = (*itr).text;
                osg::Vec3 point((*itr).position.x()- b._min.x(), (*itr).position.y()- b._min.y(), (*itr).position.z()- b._min.z());
                text->setPosition(point);
                //scenebounds.expandBy((*itr).position);
                geode->addDrawable(text);
            }
            root->addChild(geode);
        }
        // 处理尺寸标注
        if (_dimensions.size())
        {
            osg::Geode *geode = new osg::Geode;
            for (std::vector<DimensionElement>::iterator itr = _dimensions.begin();
                 itr != _dimensions.end();
                 ++itr)
            {
                // 绘制尺寸线
                if (!(*itr).lines.empty())
                {
                    osg::Vec3Array *vertices = new osg::Vec3Array;
                    for (std::vector<osg::Vec3d>::const_iterator vitr = (*itr).lines.begin();
                         vitr != (*itr).lines.end();
                         ++vitr)
                    {
                        vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                        //scenebounds.expandBy(*vitr);
                    }
                    geode->addDrawable(createLnGeometry(osg::PrimitiveSet::LINES, vertices, (*itr).color));
                }

                // 绘制箭头
                if (!(*itr).arrows.empty())
                {
                    osg::Vec3Array *vertices = new osg::Vec3Array;
                    for (std::vector<osg::Vec3d>::const_iterator vitr = (*itr).arrows.begin();
                         vitr != (*itr).arrows.end();
                         ++vitr)
                    {
                        vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                        //scenebounds.expandBy(*vitr);
                    }
                    geode->addDrawable(createLnGeometry(osg::PrimitiveSet::LINE_STRIP, vertices, (*itr).color));
                }

                // 添加文本
                osgText::Text *dimText = new osgText::Text;
                dimText->setText((*itr).text);
                dimText->setPosition(osg::Vec3((*itr).textPosition.x()- b._min.x(), (*itr).textPosition.y()- b._min.y(), (*itr).textPosition.z()- b._min.z()));
                dimText->setColor((*itr).color);
                //scenebounds.expandBy((*itr).textPosition);
                geode->addDrawable(dimText);
            }
            root->addChild(geode);
        }

        // 处理填充
        if (_hatches.size())
        {
            osg::Geode *geode = new osg::Geode;
            for (std::vector<HatchElement>::iterator itr = _hatches.begin();
                 itr != _hatches.end();
                 ++itr)
            {
                // 绘制边界
                for (std::vector<std::vector<osg::Vec3d>>::const_iterator bitr = (*itr).boundaries.begin();
                     bitr != (*itr).boundaries.end();
                     ++bitr)
                {
                    if (!(*bitr).empty())
                    {
                        osg::Vec3Array *vertices = new osg::Vec3Array;
                        for (std::vector<osg::Vec3d>::const_iterator vitr = (*bitr).begin();
                             vitr != (*bitr).end();
                             ++vitr)
                        {
                            vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                            //scenebounds.expandBy(*vitr);
                        }
                        geode->addDrawable(createLnGeometry(osg::PrimitiveSet::LINE_LOOP, vertices, (*itr).color));
                    }
                }

                // 绘制填充图案
                if (!(*itr).isSolid && !(*itr).pattern.empty())
                {
                    osg::Vec3Array *vertices = new osg::Vec3Array;
                    for (std::vector<osg::Vec3d>::const_iterator vitr = (*itr).pattern.begin();
                         vitr != (*itr).pattern.end();
                         ++vitr)
                    {
                        vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                        //scenebounds.expandBy(*vitr);
                    }
                    geode->addDrawable(createLnGeometry(osg::PrimitiveSet::LINES, vertices, (*itr).color));
                }
            }
            root->addChild(geode);
        }

        // 处理面
        if (_faces.size())
        {
            osg::Geode *geode = new osg::Geode;
            for (std::vector<FaceElement>::iterator itr = _faces.begin();
                 itr != _faces.end();
                 ++itr)
            {
                if (!(*itr).vertices.empty())
                {
                    osg::Vec3Array *vertices = new osg::Vec3Array;
                    for (std::vector<osg::Vec3d>::const_iterator vitr = (*itr).vertices.begin();
                         vitr != (*itr).vertices.end();
                         ++vitr)
                    {
                        vertices->push_back(osg::Vec3((*vitr).x()- b._min.x(), (*vitr).y()- b._min.y(), (*vitr).z()- b._min.z()));
                        //scenebounds.expandBy(*vitr);
                    }
                    geode->addDrawable(createLnGeometry(osg::PrimitiveSet::POLYGON, vertices, (*itr).color));
                }
            }
            root->addChild(geode);
        }
    }

protected:
    std::string _name;
    std::vector<PointElement> _points;
    std::vector<LineElement> _lines;
    std::vector<ColoredVertices> _linestrips;
    std::vector<ColoredVertices> _lineloops;
    std::vector<ColoredVertices> _triangles;
    std::vector<ColoredVertices> _quads;
    std::vector<TextElement> _texts;
    // 新增容器以支持更多实体类型
    std::vector<DimensionElement> _dimensions;
    std::vector<HatchElement> _hatches;
    std::vector<FaceElement> _faces;
};

class DwgScene : public osg::Referenced
{
public:
    DwgScene() {}
    virtual ~DwgScene() {}

    void pushMatrix(const osg::Matrixd &m, bool protect = false)
    {
        _mStack.push_back(_m);
        if (protect) // equivalent to setMatrix
            _m = m;
        else
            _m = _m * m;
    }
    void popMatrix()
    {
        _mStack.pop_back();
        if (_mStack.size())
            _m = _mStack.back();
        else
            _m.makeIdentity();
    }
    void ocs(const osg::Matrixd &r)
    {
        _r = r;
    }
    void blockOffset(const osg::Vec3d &t)
    {
        _t = t;
    }
    void ocs_clear()
    {
        _r.makeIdentity();
    }
    osg::Matrixd &backMatrix()
    {
        if (_mStack.size())
            return _mStack.back();
        else
            return _m;
    }

    osg::Vec3d addVertex(osg::Vec3d& v);
    osg::Vec3d addNormal(osg::Vec3d& v);
    DwgSceneLayer *findOrCreateSceneLayer(const std::string &l)
    {
        DwgSceneLayer *ly = _layers[l].get();
        if (!ly)
        {
            ly = new DwgSceneLayer(l);
            _layers[l] = ly;
        }
        return ly;
    }

    void addPoint(const std::string &l, const osg::Vec4 &color, osg::Vec3d &s);
    void addLine(const std::string &l, const osg::Vec4 &color, osg::Vec3d &s, osg::Vec3d &e);
    void addLineStrip(const std::string &l, const osg::Vec4 &color, std::vector<osg::Vec3d> &vertices);
    void addLineLoop(const std::string &l, const osg::Vec4 &color, std::vector<osg::Vec3d> &vertices);
    void addTriangles(const std::string &l, const osg::Vec4 &color, std::vector<osg::Vec3d> &vertices);
    void addQuads(const std::string &l, const osg::Vec4 &color, std::vector<osg::Vec3d> &vertices);
    void addText(const std::string &l, const osg::Vec4 &color, osg::Vec3d &point, osg::ref_ptr<osgText::Text> text);

    // 新增方法以支持更多实体类型
    void addDimension(const std::string &l,
                      const std::vector<osg::Vec3d> &lines,
                      const std::vector<osg::Vec3d> &arrows,
                      const osg::Vec3d &textPosition,
                      const std::string &text,
                      const osg::Vec4 &color);

    void addHatch(const std::string &l,
                  const std::vector<std::vector<osg::Vec3d>> &boundaries,
                  const std::vector<osg::Vec3d> &pattern,
                  const osg::Vec4 &color,
                  bool isSolid);

    void addFace(const std::string &l, const std::vector<osg::Vec3d> &vertices, const osg::Vec4 &color);

    osg::Group *scene2osg()
    {
        osg::Group *root = NULL;
        osg::Group *child = NULL;
        _b.makeMinValid();
        osg::Vec3 v = osg::Vec3(_b._min.x(), _b._min.y(), _b._min.z());
        double x = _b._min.x() - (double)v.x();
        double y = _b._min.y() - (double)v.y();
        double z = _b._min.z() - (double)v.z();
        osg::Matrixd m = osg::Matrixd::translate(v);
        root = new osg::MatrixTransform(m);
        if (x || y || z)
        {
            m = osg::Matrixd::translate(x, y, z);
            child = new osg::MatrixTransform(m);
            root->addChild(child);
        }
        else
        {
            child = root;
        }
        //            root = mt;

        child->setName("Layers");

        // Add layers to the child
        for (std::map<std::string, osg::ref_ptr<DwgSceneLayer>>::iterator litr = _layers.begin();
             litr != _layers.end(); ++litr)
        {
            DwgSceneLayer *ly = (*litr).second.get();
            if (!ly)
                continue;
            osg::Group *lg = new osg::Group;
            lg->setName((*litr).first);
            child->addChild(lg);
            ly->layer2osg(lg, _b);
        }
        return root;
    }

protected:
    osg::Matrixd _m;
    osg::Matrixd _r;
    osg::Vec3d _t;
    bounds _b;
    std::map<std::string, osg::ref_ptr<DwgSceneLayer>> _layers;
    std::vector<osg::Matrixd> _mStack;
};

#endif // DWG_SCENE_H